package com.ant.common.utils;

import com.ant.business.system.vo.UserVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @author LB
 */
@Slf4j
public class LocalBeanUtil {

    private static final String CREATOR = "creator";
    private static final String CREATE_TIME = "createTime";
    private static final String EDITOR = "editor";
    private static final String EDIT_TIME = "editTime";
    private static final String UNIT_ID = "unitId";
    private static final String DELETE_FLAG = "deleteFlag";

    /**
     * Object 转 Object
     */
    public static <T, O> O copyProperties(T source, Class<O> newClass) throws Exception {
        if (source == null) {
            return null;
        }
        O object = newClass.newInstance();
        BeanUtils.copyProperties(source, object);
        return object;
    }

    /**
     * List 转 List
     */
    public static <T, O> List<O> copyProperties(List<T> source, Class<O> newClass) throws Exception {
        if (Objects.isNull(source)) {
            return new ArrayList<>();
        }
        List<O> result = new ArrayList<>();
        for (T t : source) {
            O object = copyProperties(t, newClass);
            result.add(object);
        }
        return result;
    }

    /**
     * 判断实体类里是否有该字段
     *
     * @param c
     * @param fieldName
     * @return
     */
    public static boolean hasField(Class c, String fieldName) {
        Field[] fields = c.getDeclaredFields();
        for (Field f : fields) {
            if (fieldName.equals(f.getName())) {
                return true;
            }
        }

        Field[] supperFields = c.getSuperclass().getDeclaredFields();
        for (Field f : supperFields) {
            if (fieldName.equals(f.getName())) {
                return true;
            }
        }
        return false;
    }

    /**
     * 给登录信息赋值
     *
     * @param o
     */
    public static void setLoginUserInfo(Object o) {
        try {
            UserVo user = UserThreadLocal.getUser();
            if (Objects.nonNull(user)) {
                LocalBeanUtil.setLoginUserInfo(o, user.getUserName(), user.getUnitId());
            }
        } catch (Exception e) {
            log.error("反射赋值登录人信息时出错：" + e.getMessage());
        }
    }

    /**
     * 给登录信息赋值
     *
     * @param o
     */
    public static void setLoginUserInfo(Object o, UserVo user) {
        try {
            if (Objects.nonNull(user)) {
                LocalBeanUtil.setLoginUserInfo(o, user.getUserName(), user.getUnitId());
            }
        } catch (Exception e) {
            log.error("反射赋值登录人信息时出错：" + e.getMessage());
        }
    }

    /**
     * 给登录信息赋值
     *
     * @param o
     */
    public static void setLoginUserInfo(Object o, String userName, Integer unitId) {
        try {
            //反射得到本类的的字段列表
            Field[] declaredFields = o.getClass().getDeclaredFields();
            //反射得到父类的字段列表
            Field[] supplierFields = o.getClass().getSuperclass().getDeclaredFields();

            //循环父类
            for (Field supplierField : supplierFields) {
                Object val = null;

                if (CREATOR.equals(supplierField.getName())) {
                    val = userName;
                } else if (CREATE_TIME.equals(supplierField.getName())) {
                    val = System.currentTimeMillis();
                } else if (EDITOR.equals(supplierField.getName())) {
                    val = userName;
                } else if (EDIT_TIME.equals(supplierField.getName())) {
                    val = System.currentTimeMillis();
                } else if (UNIT_ID.equals(supplierField.getName())) {
                    val = unitId;
                } else if (DELETE_FLAG.equals(supplierField.getName())) {
                    val = DELETE_STATUS.UN_DELETE.getCode();
                }

                if (Objects.nonNull(val)) {
                    if (supplierField.isAccessible()) {
                        supplierField.set(o, val);
                    } else {
                        supplierField.setAccessible(true);
                        supplierField.set(o, val);
                        supplierField.setAccessible(false);
                    }
                }
            }

            //循环本类
            for (Field field : declaredFields) {
                Object val = null;

                if (CREATOR.equals(field.getName())) {
                    val = userName;
                } else if (CREATE_TIME.equals(field.getName())) {
                    val = System.currentTimeMillis();
                } else if (EDITOR.equals(field.getName())) {
                    val = userName;
                } else if (EDIT_TIME.equals(field.getName())) {
                    val = System.currentTimeMillis();
                } else if (UNIT_ID.equals(field.getName())) {
                    val = unitId;
                } else if (DELETE_FLAG.equals(field.getName())) {
                    val = DELETE_STATUS.UN_DELETE.getCode();
                }

                if (Objects.nonNull(val)) {
                    if (field.isAccessible()) {
                        field.set(o, val);
                    } else {
                        field.setAccessible(true);
                        field.set(o, val);
                        field.setAccessible(false);
                    }
                }
            }
        } catch (Exception e) {
            log.error("反射赋值登录人信息时出错：" + e.getMessage());
        }
    }

    /**
     * 给登录信息赋值
     *
     * @param o
     */
    public static void updateLoginUserInfo(Object o) {
        try {
            UserVo user = UserThreadLocal.getUser();
            if (Objects.nonNull(user)) {
                LocalBeanUtil.updateLoginUserInfo(o, user.getUserName());
            }
        } catch (Exception e) {
            log.error("反射赋值登录人信息时出错：" + e.getMessage());
        }
    }

    /**
     * 给登录信息赋值
     *
     * @param o
     */
    public static void updateLoginUserInfo(Object o, String userName) {
        try {
            Field[] declaredFields = o.getClass().getDeclaredFields();
            Field[] supplierFields = o.getClass().getSuperclass().getDeclaredFields();

            for (Field supplierField : supplierFields) {
                Object val = null;

                if (EDITOR.equals(supplierField.getName())) {
                    val = userName;
                } else if (EDIT_TIME.equals(supplierField.getName())) {
                    val = System.currentTimeMillis();
                }

                if (Objects.nonNull(val)) {
                    if (supplierField.isAccessible()) {
                        supplierField.set(o, val);
                    } else {
                        supplierField.setAccessible(true);
                        supplierField.set(o, val);
                        supplierField.setAccessible(false);
                    }
                }
            }

            for (Field field : declaredFields) {
                Object val = null;

                if (EDITOR.equals(field.getName())) {
                    val = userName;
                } else if (EDIT_TIME.equals(field.getName())) {
                    val = System.currentTimeMillis();
                }

                if (Objects.nonNull(val)) {
                    if (field.isAccessible()) {
                        field.set(o, val);
                    } else {
                        field.setAccessible(true);
                        field.set(o, val);
                        field.setAccessible(false);
                    }
                }
            }
        } catch (Exception e) {
            log.error("反射赋值登录人信息时出错：" + e.getMessage());
        }
    }


    /**
     * 删除状态
     */
    public enum DELETE_STATUS {
        UN_DELETE("未删除", 0),
        DELETED("已删除", 1);

        private Integer code;
        private String name;

        DELETE_STATUS(String name, Integer code) {
            this.name = name;
            this.code = code;
        }

        public int getCode() {
            return code;
        }

        public String getName() {
            return name;
        }
    }
}
